package com.example.device;

import com.example.circuit.CircuitSignalParsing;
import com.example.circuit.CircuitSignalParsingEnum;
import com.example.utils.Utils;
import com.example.wire.Wire;

import java.util.HashMap;
import java.util.LinkedList;
import java.util.Map;
import java.util.Queue;

public abstract class DeviceAbs extends Thread implements Device{
    private final Map<Integer,Queue<Byte>> sendMap = new HashMap<>();//储存电信号
    private final Map<Integer,Queue<Byte>> receiveMap = new HashMap<>();//储存bite流
    Map<Integer,Wire> wireMap = new HashMap<Integer,Wire>();
    Map<Integer,Byte> synchronousMap = new HashMap<Integer,Byte>();
    //TODO:信号处理，在读入信号载入缓冲区，输出信号载入缓冲区时转码
    CircuitSignalParsing CSP = CircuitSignalParsingEnum.NoCode;
    DeviceState DS= DeviceState.INTERVAL;

    @Override
    public void setCircuitSignalParsing(CircuitSignalParsing circuitSignalParsing) {
        CSP = circuitSignalParsing;
    }

    public void connect(int port, Wire wire){
        wireMap.put(port,wire);
        synchronousMap.put(port, (byte) 0);
        sendMap.put(port,new LinkedList<Byte>());
        receiveMap.put(port,new LinkedList<Byte>());
    }

    /**
     * 一切从物理层对receive的写入都需要调用该方法，或者自行实现解码过程
     * @param port
     */
    public void receive(int port){
        Byte b;
        //此处锁十分重要，切误删去
        synchronized (wireMap.get(port)) {
           b = wireMap.get(port).receiveByte();
        }
        synchronousMap.replace(port,b,
                CSP.decode(receiveMap.get(port),b,synchronousMap.get(port)));
        if (DS == DeviceState.INTERVAL && b!=null){
            DS = DeviceState.WORKING;
        }
    }

    /**
     * 一切往物理层发送的电信号的行为，建议通过调用该方法实现
     * @param port
     */
    public void send(int port){
        Byte b = sendMap.get(port).poll();
        if (b!=null){
            wireMap.get(port).sendByte(b);
            if (DS == DeviceState.INTERVAL){
                DS = DeviceState.WORKING;
            }
        }
    }

    @Override
    public void run() {
        int multipleTimeDelay = 0;//时延倍数
        while (true){
            DS = DeviceState.INTERVAL;
            for (int port:receiveMap.keySet()){
                send(port);
                receive(port);
            }
            Thread.yield();

            if (DS == DeviceState.WORKING){
                multipleTimeDelay = 0;
            }else {
                multipleTimeDelay+= 1;
                try {
                    Thread.sleep((long) multipleTimeDelay * Utils.TimeDelay);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }


    //TODO:以下方法仅用于测试
    public void _setSendStr(int port, String sendStr){
        Utils.setQueue(sendStr,sendMap.get(port),CSP);
    }
    public String _getSendStr(int port){
        return Utils.getString(sendMap.get(port));
    }
    public void _setReceiveStr(int port, String receiveStr){
        Utils.setQueue(receiveStr,receiveMap.get(port),CircuitSignalParsingEnum.NoCode);
    }
    public String _getReceiveStr(int port){
        return Utils.getString(receiveMap.get(port));
    }
    public void _sendAllToWire(){
        for (int port:wireMap.keySet()){
            while (!sendMap.get(port).isEmpty()){
                send(port);
            }
        }
    }
    public void _getAllFromWire(){
        for (int port:wireMap.keySet()){
            while (!wireMap.get(port).isReceiveEmpty()){
                receive(port);
            }
        }
    }
}
